home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / util4 / cliphn12.lha / Src / clip-handler.c
C/C++ Source or Header  |  1995-11-21  |  14KB  |  492 lines

  1. /*
  2. **    clip-handler.c
  3. **    DOS handler for Clipboard access
  4. **    Copyright © 1995 Michael Letowski
  5. */
  6.  
  7. #define __USE_SYSBASE
  8.  
  9. #include <exec/types.h>
  10. #include <exec/execbase.h>
  11. #include <exec/memory.h>
  12. #include <dos/dos.h>
  13. #include <dos/dosextens.h>
  14. #include <dos/filehandler.h>
  15. #include <libraries/iffparse.h>
  16. #include <devices/clipboard.h>
  17. #include <support/types.h>
  18. #include <support/exec.h>
  19. #include <support/dos.h>
  20.  
  21. #include <string.h>
  22.  
  23. #include <proto/exec.h>
  24. #include <proto/dos.h>
  25. #include <proto/iffparse.h>
  26.  
  27. #include "clip-handler.rev.h"
  28.  
  29.  
  30. /****** clip-handler/clip_handler() *****************************************
  31. *
  32. *   NAME
  33. *       clip_handler -- a handler for clipboard access. (V37)
  34. *
  35. *   SYNOPSIS
  36. *       Open("CLIP:[unit_num]");
  37. *
  38. *   FUNCTION
  39. *       Clip-handler allows AmigaDOS to interface to a standard clipboard
  40. *       device. Clip-handler takes data from an application, packs it into
  41. *       FTXT CHRS format and stores in clipboard. Or it takes data FTXT CHRS
  42. *       data from the clipboard and passes it into an application.
  43. *
  44. *   INPUTS
  45. *       unit_num - clipboard.device unit number. Must be in 0-255 range.
  46. *                  Default values is PRIMARY_CLIP.
  47. *
  48. *   PACKETS
  49. *       ACTION_FINDINPUT
  50. *       ACTION_FINDOUTPUT
  51. *       ACTION_READ
  52. *       ACTION_WRITE
  53. *       ACTION_END
  54. *       ACTION_DIE
  55. *       ACTION_IS_FILESYSTEM
  56. *
  57. *   MOUNTLIST ENTRIES
  58. *       This is default mountlist entry used for clip-handler:
  59. *
  60. *              CLIP:   Handler   = L:clip-handler
  61. *                      Priority  = 5
  62. *                      StackSize = 4096
  63. *                      GlobVec   = -1
  64. *              #
  65. *
  66. *   NOTES
  67. *       At present only FTXT CHRS chunks are recognized and utilized.
  68. *
  69. *   EXAMPLES
  70. *       Store Startup-Sequence in default clipboard unit:
  71. *              Copy S:Startup-Sequence CLIP:
  72. *
  73. *       Get directory's listing and place it in clipboard unit 1:
  74. *              List >CLIP:1
  75. *
  76. *       View clipboard's contents
  77. *              Type CLIP:
  78. *
  79. *   BUGS
  80. *       Accessing CLIP: for reading and writing at the same time will hang
  81. *       clip-handler.
  82. *       Neither appending data (ACTION_FINDUPDATE) nor seeking (ACTION_SEEK)
  83. *       is supported yet.
  84. *
  85. *   SEE ALSO
  86. *       clipboard.device, iffparse.library.
  87. *
  88. *****************************************************************************
  89. *
  90. */
  91.  
  92.  
  93. /*
  94. **    Constants
  95. */
  96. #define DOS_NAME        "dos.library"
  97. #define DOS_VERN        37L
  98. #define IFFP_NAME        "iffparse.library"
  99. #define IFFP_VERN        37L
  100.  
  101. #define ID_FTXT            MAKE_ID('F','T','X','T')
  102. #define ID_CHRS            MAKE_ID('C','H','R','S')
  103.  
  104. #define PATH_SIZE        256
  105.  
  106.  
  107. /*
  108. **    Macros
  109. */
  110. #define SetPktRes(pkt,res1,res2)    ((pkt)->dp_Res1=(res1),(pkt)->dp_Res2=(res2))
  111.  
  112.  
  113. /*
  114. **    Globals
  115. */
  116. STATIC CONST TEXT VersionString[]=
  117.     VERSION(PROG_NAME,PROG_VERSION,PROG_REVISION,PROG_DATE);
  118.  
  119. /* Library bases */
  120. struct ExecBase *SysBase;
  121. struct DosLibrary *DOSBase;
  122. struct Library *IFFParseBase;
  123.  
  124.  
  125. /*
  126. **    Private prototypes
  127. */
  128. /*    Packet routines    */
  129. STATIC struct DosPacket *WaitPacket(struct MsgPort *port);
  130. STATIC VOID ReplyPacket(struct DosPacket *packet, struct MsgPort *port);
  131. STATIC VOID ReplyPacketRes(struct DosPacket *packet, struct MsgPort *port,
  132.                                                         LONG res1, LONG res2);
  133. STATIC VOID FlushPackets(struct MsgPort *port);
  134.  
  135. /*    clip-handler routines    */
  136. STATIC struct IFFHandle *OpenCH(struct DosPacket *packet);
  137. STATIC VOID CloseCH(struct IFFHandle *iff);
  138. STATIC LONG OpenInputCH(struct DosPacket *packet);
  139. STATIC LONG OpenOutputCH(struct DosPacket *packet);
  140. #ifdef DO_SEEK
  141. STATIC LONG OpenUpdateCH(struct DosPacket *packet);
  142. #endif
  143. STATIC LONG CloseIOUCH(struct DosPacket *packet);
  144. STATIC VOID ReadClipboard(struct DosPacket *packet);
  145. STATIC VOID WriteClipboard(struct DosPacket *packet);
  146. #ifdef DO_SEEK
  147. STATIC VOID SeekClipboard(struct DosPacket *packet);
  148. #endif
  149. STATIC LONG IFF2DOS(LONG iffError);
  150.  
  151.  
  152. /*
  153. **    Public functions
  154. */
  155. SAVEDS LONG ClipHandler(VOID)
  156. {
  157.     struct Library *LocalDOSBase;
  158.     struct Library *LocalIFFParseBase;
  159.  
  160.     struct Process *PR;
  161.     struct MsgPort *MP,*PacketPort;
  162.     struct DosPacket *Pkt;
  163.     struct DeviceNode *DevNode;
  164.     LBOOL Done=FALSE;
  165.     ULONG OpenCount=0;
  166.  
  167.     SysBase=INITSYSBASE;                                                    /* Set up SysBase */
  168.     PR=ThisProcessS;
  169.     MP=&PR->pr_MsgPort;
  170.  
  171.     if(PR->pr_CLI)                                                                /* Run from shell? */
  172.         return(RETURN_FAIL);                                                /* Failure */
  173.  
  174.     Pkt=WaitPacket(MP);                                                        /* Get startup message */
  175.     try(DevNode=(struct DeviceNode *)BADDR(Pkt->dp_Arg3),NO_DEV);
  176.  
  177.     /* Open libraries */
  178.     unless(LocalDOSBase=OpenLibrary(DOS_NAME,DOS_VERN))
  179.         throw2(ReplyPacketRes(Pkt,MP,DOSFALSE,ERROR_INVALID_RESIDENT_LIBRARY),    NO_DOS);
  180.     unless(LocalIFFParseBase=OpenLibrary(IFFP_NAME,IFFP_VERN))
  181.         throw2(ReplyPacketRes(Pkt,MP,DOSFALSE,ERROR_INVALID_RESIDENT_LIBRARY),    NO_IFFP);
  182.  
  183.     /* Create port */
  184.     unless(PacketPort=CreateMsgPort())
  185.         throw2(ReplyPacketRes(Pkt,MP,DOSFALSE,ERROR_NO_FREE_STORE),    NO_PORT);
  186.  
  187.     /* Set up global bases */
  188.     DOSBase=(struct DosLibrary *)LocalDOSBase;        /* Set up global bases */
  189.     IFFParseBase=LocalIFFParseBase;
  190.     DevNode->dn_Task=PacketPort;
  191.     Pkt->dp_Arg4=(LONG)PacketPort;
  192.     ReplyPacketRes(Pkt,PacketPort,DOSTRUE,Pkt->dp_Res2);
  193.  
  194.     while(!Done)
  195.     {
  196.         Pkt=WaitPacket(PacketPort);
  197.         switch(Pkt->dp_Type)
  198.         {
  199.             case ACTION_FINDINPUT:                                        /* (handle,lock,name) -> success */
  200.                 OpenCount+=OpenInputCH(Pkt);
  201.                 break;
  202.             case ACTION_FINDOUTPUT:                                        /* (handle,lock,name) -> success */
  203.                 OpenCount+=OpenOutputCH(Pkt);
  204.                 break;
  205. #ifdef DO_SEEK
  206.             case ACTION_FINDUPDATE:                                        /* (handle,lock,name) -> success */
  207.                 OpenCount+=OpenUpdateCH(Pkt);
  208.                 break;
  209. #endif
  210.             case ACTION_END:                                                    /* (handle) -> success */
  211.                 OpenCount-=CloseIOUCH(Pkt);
  212.                 break;
  213.             case ACTION_READ:                                                    /* (handle,buffer,len) -> cnt */
  214.                 ReadClipboard(Pkt);
  215.                 break;
  216.             case ACTION_WRITE:                                                /* (handle,buffer,len) -> cnt */
  217.                 WriteClipboard(Pkt);
  218.                 break;
  219. #ifdef DO_SEEK
  220.             case ACTION_SEEK:
  221.                 SeekClipboard(Pkt);
  222.                 break;
  223. #endif
  224.             case ACTION_DIE:
  225.                 if(OpenCount)
  226.                     SetPktRes(Pkt,DOSFALSE,ERROR_OBJECT_IN_USE);
  227.                 else
  228.                 {
  229.                     SetPktRes(Pkt,DOSTRUE,0);
  230.                     Done=TRUE;
  231.                 }
  232.                 break;
  233.             case ACTION_IS_FILESYSTEM:
  234.                 SetPktRes(Pkt,DOSFALSE,0);
  235.                 break;
  236.             default:
  237.                 SetPktRes(Pkt,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
  238.                 break;
  239.         }
  240.         ReplyPacket(Pkt,PacketPort);
  241.     }
  242.     Forbid();                                                                            /* Disable task switching */
  243.     DevNode->dn_Task=NULL;                                                /* Switch off device */
  244.     FlushPackets(PacketPort);                                            /* Discard waiting packets */
  245.     UnLoadSeg(DevNode->dn_SegList);                                /* Unload code */
  246.     DevNode->dn_SegList=NULL;                                            /* And mark this fact */
  247.     Permit();                                                                            /* Enable task switching */
  248.  
  249.     catch(NO_PORT,    DeleteMsgPort(PacketPort));
  250.     catch(NO_IFFP,    CloseLibrary(LocalIFFParseBase));
  251.     catch(NO_DOS,        CloseLibrary(LocalDOSBase));
  252.     catch(NO_DEV,        );
  253.     return(0);
  254. }    /* ClipHandler */
  255.  
  256.  
  257. /*
  258. **    Private functions
  259. */
  260. STATIC struct DosPacket *WaitPacket(struct MsgPort *port)
  261. {
  262.     WaitPort(port);
  263.     return((struct DosPacket *)GetMsg(port)->mn_Node.ln_Name);
  264. }    /* WaitPacket */
  265.  
  266. STATIC VOID ReplyPacket(struct DosPacket *packet, struct MsgPort *port)
  267. {
  268.     struct MsgPort *ReplyPort=packet->dp_Port;
  269.  
  270.     packet->dp_Port=port;
  271.     packet->dp_Link->mn_Node.ln_Name=(STRPTR)packet;
  272.     PutMsg(ReplyPort,packet->dp_Link);
  273. }    /* ReplyPacket */
  274.  
  275. STATIC VOID ReplyPacketRes(struct DosPacket *packet, struct MsgPort *port,
  276.                                                         LONG res1, LONG res2)
  277. {
  278.     SetPktRes(packet,res1,res2);
  279.     ReplyPacket(packet,port);
  280. }    /* ReplyPacketRes */
  281.  
  282. STATIC VOID FlushPackets(struct MsgPort *port)
  283. {
  284.     struct DosPacket *Packet;
  285.  
  286.     while(Packet=(struct DosPacket *)GetMsg(port)->mn_Node.ln_Name)
  287.         ReplyPacketRes(Packet,port,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
  288. }    /* FlushPackets */
  289.  
  290. STATIC struct IFFHandle *OpenCH(struct DosPacket *packet)
  291. {
  292.     CHAR Name[PATH_SIZE];
  293.     STRPTR Str=(STRPTR)BADDR(packet->dp_Arg3);
  294.     struct FileHandle *Handle=FH(packet->dp_Arg1);
  295.     struct IFFHandle *IFF;
  296.     LONG Unit;
  297.  
  298.     SetPktRes(packet,DOSFALSE,0);
  299.     Handle->fh_Arg1=0;
  300.     Handle->fh_Port=NULL;                                                    /* Non-interactive file */
  301.  
  302.     memcpy(Name,&Str[1],Str[0]);                                    /* Copy data */
  303.     Name[Str[0]]='\0';                                                        /* NULL-terminate */
  304.  
  305.     Str=Name;
  306.     if(Str=strchr(Str,':'))                                                /* Device name given */
  307.         Str++;                                                                            /* Skip the colon */
  308.     StrToLong(Str,&Unit);                                                    /* <Unit> gets set to 0 in case of error */
  309.  
  310.     unless(IFF=AllocIFF())
  311.         throw2(packet->dp_Res2=ERROR_NO_FREE_STORE,    NO_IFF);
  312.     unless(IFF->iff_Stream=(ULONG)OpenClipboard(Unit))
  313.         throw2(packet->dp_Res2=ERROR_NO_FREE_STORE,    NO_CLIPBOARD);    /* FIX: error */
  314.     InitIFFasClip(IFF);
  315.     Handle->fh_Arg1=(LONG)IFF;
  316.     packet->dp_Res1=DOSTRUE;
  317.     return(IFF);
  318.  
  319.     /* Exceptions */
  320.     catch(FOO,                    );
  321.     catch(NO_CLIPBOARD,    CloseClipboard((struct ClipboardHandle *)IFF->iff_Stream));
  322.     catch(NO_IFF,                FreeIFF(IFF));
  323.     return(NULL);
  324. }    /* OpenCH */
  325.  
  326. STATIC VOID CloseCH(struct IFFHandle *iff)
  327. {
  328.     CloseClipboard((struct ClipboardHandle *)iff->iff_Stream);
  329.     FreeIFF(iff);
  330. }    /* CloseCH */
  331.  
  332. STATIC LONG OpenInputCH(struct DosPacket *packet)
  333. {
  334.     struct IFFHandle *IFF;
  335.     struct ContextNode *CN;
  336.     LONG Error;
  337.  
  338.     try(IFF=OpenCH(packet),                                                    NO_HANDLE);
  339.     try(!(Error=OpenIFF(IFF,IFFF_READ)),                        NO_IFF);
  340.     try(!(Error=StopChunk(IFF,ID_FTXT,ID_CHRS)),        IFF_ERROR);
  341.     try(!(Error=ParseIFF(IFF,IFFPARSE_SCAN)),                IFF_ERROR);
  342.     try(CN=CurrentChunk(IFF),                                                IFF_ERROR);
  343.     try(CN->cn_Type==ID_FTXT && CN->cn_ID==ID_CHRS,    IFF_ERROR);
  344.     return(1);                                                                        /* Open succesfull */
  345.  
  346.     catch(IFF_ERROR,    );
  347.     catch(NO_IFF,            CloseIFF(IFF));
  348.     SetPktRes(packet,DOSFALSE,IFF2DOS(Error));        /* Set result */
  349.     catch(NO_HANDLE,    CloseCH(IFF));
  350.     return(0);                                                                        /* Open failed */
  351. }    /* OpenInputCH */
  352.  
  353. STATIC LONG OpenOutputCH(struct DosPacket *packet)
  354. {
  355.     struct IFFHandle *IFF;
  356.     LONG Error;
  357.  
  358.     try(IFF=OpenCH(packet),                                                                                NO_HANDLE);
  359.     try(!(Error=OpenIFF(IFF,IFFF_WRITE)),                                                    NO_IFF);
  360.     try(!(Error=PushChunk(IFF,ID_FTXT,ID_FORM,IFFSIZE_UNKNOWN)),    IFF_ERROR);
  361.     try(!(Error=PushChunk(IFF,0,ID_CHRS,IFFSIZE_UNKNOWN)),                IFF_ERROR);
  362.     return(1);                                                                        /* Open succesfull */
  363.  
  364.     catch(IFF_ERROR,    );
  365.     catch(NO_IFF,            CloseIFF(IFF));
  366.     SetPktRes(packet,DOSFALSE,IFF2DOS(Error));        /* Set result */
  367.     catch(NO_HANDLE,    CloseCH(IFF));
  368.     return(0);                                                                        /* Open failed */
  369. }    /* OpenOutputCH */
  370.  
  371. #ifdef DO_SEEK
  372. STATIC LONG OpenUpdateCH(struct DosPacket *packet)
  373. {
  374.     struct IFFHandle *IFF;
  375.     LONG Error;
  376.  
  377.     try(IFF=OpenCH(packet),                                                NO_HANDLE);
  378.     try(!(Error=OpenIFF(IFF,IFFF_WRITE)),                    NO_IFF);
  379.     try(!(Error=StopChunk(IFF,ID_FTXT,ID_CHRS)),    IFF_ERROR);
  380.         /* FIX: Should use write mode here */
  381.     try(!(Error=ParseIFF(IFF,IFFPARSE_SCAN)),            IFF_ERROR);
  382.     return(1);                                                                        /* Open succesfull */
  383.  
  384.     catch(IFF_ERROR,    );
  385.     catch(NO_IFF,            CloseIFF(IFF));
  386.     SetPktRes(packet,DOSFALSE,IFF2DOS(Error));        /* Set result */
  387.     catch(NO_HANDLE,    CloseCH(IFF));
  388.     return(0);                                                                        /* Open failed */
  389. }    /* OpenUpdateCH */
  390. #endif
  391.  
  392. STATIC LONG CloseIOUCH(struct DosPacket *packet)
  393. {
  394.     struct IFFHandle *IFF=(struct IFFHandle *)packet->dp_Arg1;
  395.  
  396. #if 0
  397.     /* FIX:??? Check PopChunk() for errors */
  398.     if(ftst(IFF->iff_Flags,IFFF_WRITE))                        /* Write mode */
  399.         if(PopChunk(IFF)==0)                                                /* Close CHRS */
  400.             PopChunk(IFF);                                                        /* Close FTXT */
  401. #endif
  402.     CloseIFF(IFF);
  403.     CloseCH(IFF);
  404.     SetPktRes(packet,DOSTRUE,0);                                    /* Set result */
  405.     return(1);
  406. }    /* CloseIOUCH */
  407.  
  408. STATIC VOID ReadClipboard(struct DosPacket *packet)
  409. {
  410.     struct IFFHandle *IFF=(struct IFFHandle *)packet->dp_Arg1;
  411.     STRPTR Buffer=(STRPTR)packet->dp_Arg2;
  412.     LONG ReadCnt,Bytes=packet->dp_Arg3;
  413.  
  414.     SetPktRes(packet,-1,0);                                                /* Set result */
  415.  
  416.     ReadCnt=ReadChunkBytes(IFF,Buffer,Bytes);            /* Read into buffer */
  417.     if(ReadCnt<0)    packet->dp_Res2=IFF2DOS(ReadCnt);
  418.     else                    packet->dp_Res1=ReadCnt;
  419. }    /* ReadClipboard */
  420.  
  421. STATIC VOID WriteClipboard(struct DosPacket *packet)
  422. {
  423.     struct IFFHandle *IFF=(struct IFFHandle *)packet->dp_Arg1;
  424.     STRPTR Buffer=(STRPTR)packet->dp_Arg2;
  425.     LONG WriteCnt,Bytes=packet->dp_Arg3;
  426.  
  427.     SetPktRes(packet,-1,0);                                                /* Set result */
  428.  
  429.     WriteCnt=WriteChunkBytes(IFF,Buffer,Bytes);        /* Write buffer */
  430.     if(WriteCnt<0)    packet->dp_Res2=IFF2DOS(WriteCnt);
  431.     else                        packet->dp_Res1=WriteCnt;
  432. }    /* WriteClipboard */
  433.  
  434. #ifdef DO_SEEK
  435. STATIC VOID SeekClipboard(struct DosPacket *packet)
  436. {
  437.     struct IFFHandle *IFF=(struct IFFHandle *)packet->dp_Arg1;
  438.     struct ContextNode *CN;
  439.     LONG Offset=packet->dp_Arg2,OffsetType=packet->dp_Arg3;
  440.     LONG OldPos,NewPos=-1;
  441.  
  442.     SetPktRes(packet,-1,ERROR_SEEK_ERROR);                /* Set result */
  443.  
  444.     unless(CN=CurrentChunk(IFF))
  445.         return;
  446.     unless(CN->cn_Type==ID_FTXT && CN->cn_ID==ID_CHRS)
  447.         return;
  448.  
  449.     switch(OffsetType)
  450.     {
  451.         case OFFSET_BEGINNING:    NewPos=Offset;                            break;
  452.         case OFFSET_CURRENT:        NewPos=CN->cn_Scan+Offset;    break;
  453.         case OFFSET_END:                NewPos=CN->cn_Size-Offset;    break;
  454.         default:                                                                                        break;
  455.     }
  456.  
  457.     if(NewPos>0 && NewPos<CN->cn_Size)                        /* Can seek */
  458.     {
  459.         OldPos=CN->cn_Scan;
  460.         CN->cn_Scan=NewPos;
  461.         SetPktRes(packet,OldPos,0);
  462.     }
  463. }    /* SeekClipboard */
  464. #endif
  465.  
  466. STATIC LONG IFF2DOS(LONG iffError)
  467. {
  468.     LONG DOSError=ThisProcessS->pr_Result2;
  469.  
  470.     unless(DOSError)                                                            /* Error not set */
  471.         switch(iffError)
  472.         {
  473.             case IFFERR_NOTIFF:    DOSError=ERROR_OBJECT_NOT_FOUND;    break;
  474.             case IFFERR_NOMEM:    DOSError=ERROR_NO_FREE_STORE;            break;
  475.             case IFFERR_SEEK:        DOSError=ERROR_SEEK_ERROR;                break;
  476.             case IFFERR_NOHOOK:    DOSError=ERROR_NOT_IMPLEMENTED;        break;
  477.             default:                        DOSError=ERROR_OBJECT_WRONG_TYPE;    break;
  478.         }
  479.     return(DOSError);
  480. }    /* IFF2DOS */
  481.  
  482. #if 0
  483. STATIC LONG SeekChunk(struct IFFHandle *iff, LONG offset)
  484. {
  485.     struct IFFStreamCmd Cmd=
  486.     {
  487.         IFFCMD_SEEK,    NULL,    offset
  488.     };    /* Cmd */
  489.     return(CallHookPkt((struct Hook *)(iff+1),iff,&Cmd));
  490. }    /* SeekChunk */
  491. #endif
  492.